﻿#region Copyright Info

// 
// Majesty of Omega - The next evolution of macro management space strategy
// 
// Copyright 2007-2009 André Claaßen
// 
// This file is protected by the terms and conditions of the
// Microsoft Community License (Ms-CL 1.1), a copy of which should
// have been distributed along with this software. If not,
// you may find the license information at the following URL:
// 
// http://www.microsoft.com/resources/sharedsource/licensingbasics/communitylicense.mspx

#endregion

#region

using System.Collections.Generic;
using System.Linq;
using Majesty_of_Omega.Config;
using Majesty_of_Omega.Model.Report;
using Majesty_of_Omega.Model.Research;
using Majesty_of_Omega.Logic.Calculate;
using Majesty_of_Omega.Logic.Generator;

#if NUNIT
using NUnit.Framework;
using Test.Majesty_of_Omega.TestUtils;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute;
using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute;

#elif MBUNIT
using MbUnit.Framework;
using TestClass = MbUnit.Framework.TestFixtureAttribute;
using TestMethod = MbUnit.Framework.TestAttribute;
using TestInitialize = MbUnit.Framework.SetUpAttribute;
using TestCleanup = MbUnit.Framework.TearDownAttribute;
using ClassInitialize = MbUnit.Framework.TestFixtureSetUpAttribute;
using ClassCleanup = MbUnit.Framework.TestFixtureTearDownAttribute;
#else
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endif

#endregion

namespace Test.Majesty_of_Omega.BL.Logic
{
    /// <summary>
    /// Tests for <see cref="TechFieldResearch" /> class
    /// </summary>
    [TestClass]
    public class TestResearchCalculator
    {
        [TestMethod]
        public void TestDistributeResearchPointsForTechField()
        {
            // Very simple math for the calculation of tech levels.
            // every 100 points, one level
            TechFieldResearch research = CreateTechFieldResearch(1, 100);
            CalculateInfo calculateInfo = GameLogicHelper.CreateTestCalculateInfo();

            Assert.AreEqual(0, research.TechLevel);

            FundamentalResearchCalculator calculator = new FundamentalResearchCalculator();

            // Distributes 150 points, so we enter tech level 1
            calculator.DistributeResearchPointsForTechField(150, research, calculateInfo);
            Assert.AreEqual(1, research.TechLevel);

            // we must now have a research breakthrough in the sitreport for this turn
            Assert.AreEqual(1, calculateInfo.ReportTurn.SitReportEntries.Count);
            Assert.AreEqual(SitReportType.ResearchBreakthroughOnField,
                            calculateInfo.ReportTurn.SitReportEntries[0].ReportType
                );
        }

        /// <summary>
        /// Creates a TechFieldResearch for the first tech field in the spreadshieldls
        /// </summary>
        /// <param name="exponentBase">The exponent base.</param>
        /// <param name="costMultiplier">The cost multiplier.</param>
        /// <returns></returns>
        private static TechFieldResearch CreateTechFieldResearch(double exponentBase, double costMultiplier)
        {
            var techField = SpreadSheetManager.TechTables.TechFields[0];
            techField.Research_Cost_Exponent_Base = exponentBase;
            techField.Research_Cost_Multiplier = costMultiplier;
            return new TechFieldResearch(null, techField);
        }

        /// <summary>
        /// Tests the research points distribution.
        /// </summary>
        [TestMethod]
        public void TestResearchPointsDistribution()
        {
            CalculateInfo calculateInfo = GameLogicHelper.CreateTestCalculateInfo();
            ResearchManager researchManager = new ResearchManager();

            int sumPoints = researchManager.TechFieldResearchs.Sum(tfr => tfr.ResearchPointsAccumulated);
            Assert.AreEqual(0, sumPoints);

            const int expectedValue = 255;
            FundamentalResearchCalculator calculator = new FundamentalResearchCalculator();
            calculator.DistributeFundamentalResearchPoints(expectedValue, researchManager, calculateInfo);
            int sumPointsAfterDistribution = researchManager.TechFieldResearchs.Sum(tfr => tfr.ResearchPointsAccumulated);
            Assert.AreEqual(expectedValue, sumPointsAfterDistribution);
        }

        /// <summary>
        /// Tests the <see cref="FundamentalResearchCalculator.AreAllTechFieldDependenciesResearched" /> function
        /// </summary>
        /// <example>
        /// <![CDATA[
        ///     <ns1:TechField ColumnHeadingsStart="Astro-Engineering" 
        ///           Field_Dependencies="MatSc_08,AstPh_08" Research_Cost_Multiplier="86.2096" Research_Cost_Exponent_Base="1.16" />
        /// ]]>
        /// </example>
        [Test]
        public void TestAreAllTechFieldDependenciesResearched()
        {
            ResearchManager researchManager = new ResearchManager();
            var techFieldResearch = new List<TechFieldDependency>
                                        {
                                            new TechFieldDependency("MatSc", 8),
                                            new TechFieldDependency("AstPh", 8)
                                        };
            bool researched = FundamentalResearchCalculator.AreAllTechFieldDependenciesResearched(researchManager, techFieldResearch);
            Assert.AreEqual(false, researched, "At first, all dependend tech fields must be unresearched");
            SetTechFieldResearched(researchManager, "MatSc", 7);
            SetTechFieldResearched(researchManager, "AstPh", 8);
            bool researched2 = FundamentalResearchCalculator.AreAllTechFieldDependenciesResearched(researchManager, techFieldResearch);
            Assert.AreEqual(false, researched2, "the tech fields shouldn't be researched, caus the matsc isn't at level 8");

            SetTechFieldResearched(researchManager, "MatSc", 8);
            SetTechFieldResearched(researchManager, "AstPh", 8);
            bool researched3 = FundamentalResearchCalculator.AreAllTechFieldDependenciesResearched(researchManager, techFieldResearch);
            Assert.AreEqual(true, researched3, "finally, all tech fields should be researched");
        }

        /// <summary>
        /// Sets the tech field researched.
        /// </summary>
        /// <param name="researchManager">The research manager.</param>
        /// <param name="techId">The tech id.</param>
        /// <param name="techLevel">The tech level.</param>
        private static void SetTechFieldResearched(ResearchManager researchManager, string techId, int techLevel)
        {
            var techMatScience = researchManager.GetTechFieldResearch(techId);
            techMatScience.Researched = true;
            techMatScience.TechLevel = techLevel;
        }

        /// <summary>
        /// Tests the <see cref="FundamentalResearchCalculator.DiscoverUnlockableTechFields" /> function
        /// </summary>
        /// <example>
        /// look at Planetology in TechTables.xml
        /// </example>
        [Test]
        public void TestDiscoverUnlockableTechFields()
        {
            ResearchManager researchManager = new ResearchManager();

            // first, we have no unlockable techs

            var unlockableTechs1 = FundamentalResearchCalculator.DiscoverUnlockableTechFields(researchManager);
            Assert.AreEqual(0, unlockableTechs1.Count());

            // now we unlock a dependend technologies for Astro Engineering

            SetTechFieldResearched(researchManager, "AstPh", 8);
            var unlockableTechs2 = FundamentalResearchCalculator.DiscoverUnlockableTechFields(researchManager);

            Assert.AreEqual(1, unlockableTechs2.Count());
            TechFieldResearch techFieldResearch = unlockableTechs2.First();
            Assert.AreEqual("Plane", techFieldResearch.TechField.Type_ID);
        }

        /// <summary>
        /// Tests the <see cref="FundamentalResearchCalculator.DiscoverUnlockableTechnologies" /> function
        /// </summary>
        [Test]
        public void TestDiscoverUnlockableTechnologies()
        {
            ResearchManager manager = new ResearchManager();
            IEnumerable<TechApplication> unlockableTechnologies = FundamentalResearchCalculator.DiscoverUnlockableTechnologies(manager);
            Assert.AreEqual(0, unlockableTechnologies.Count(), "Default, there are no undiscovered technologies");

            // Set tech level vor field "Bio Harvest" = 2 to unlock tech app Hydroponic Farms
            SetResearchToLevel(manager, "BioHa", 2);
            IEnumerable<TechApplication> unlockableTechnologies2 = FundamentalResearchCalculator.DiscoverUnlockableTechnologies(manager);
            
            // now we must receive the Hydro farm
            Assert.AreEqual(1, unlockableTechnologies2.Count(), "One technology found");
            Assert.AreEqual(SpreadSheetManager.TechTables.TechAppDictionary["HydroFrm"],
                unlockableTechnologies2.First()
                );
        
        }

        /// <summary>
        /// Sets the research to level.
        /// </summary>
        /// <param name="manager">The manager.</param>
        /// <param name="techId">The tech id.</param>
        /// <param name="techLevel">The tech level.</param>
        /// <returns></returns>
        private static void SetResearchToLevel(ResearchManager manager, string techId, int techLevel)
        {
            manager.GetTechFieldResearch(techId).TechLevel = techLevel;
        }

        /// <summary>
        /// Tests the <see cref="FundamentalResearchCalculator.UnlockNewTechnologies" /> function
        /// </summary>
        [Test]
        public void TestUnlockNewTechnologies()
        {
            FundamentalResearchCalculator fundamentalResearchCalculator = CreateTestResearchCalculator();
            SetResearchToLevel(fundamentalResearchCalculator.CalculateInfo.Player.ResearchManager, "BioHa", 2);
            
            // discover the hydroponic farm
            fundamentalResearchCalculator.UnlockNewTechnologies();
            
            Assert.AreEqual(1, fundamentalResearchCalculator.SitReportTurn.SitReportEntries.Count);
            Assert.IsTrue(fundamentalResearchCalculator.SitReportTurn.SitReportEntries[0].Description.Contains("Hydroponic Farms"));
        }


        /// <summary>
        /// Tests the <see cref="TechFieldResearch.RecalculateProgressInPercent" /> function
        /// </summary>
        [Test]
        public void TestReCalculateProgressInPercentWithNoProgress()
        {
            const int techLevel = 1;
            const int accumulatedPoints = 100;
            const int expectedProgress = 0;

            AssertRecalculateProgress(techLevel, accumulatedPoints, expectedProgress);
        }

        /// <summary>
        /// Tests the <see cref="TechFieldResearch.RecalculateProgressInPercent" /> function
        /// </summary>
        [Test]
        public void TestReCalculateProgressInPercentWithProgress()
        {
            const int techLevel = 1;
            const int accumulatedPoints = 150;
            const int expectedProgress = 50;

            AssertRecalculateProgress(techLevel, accumulatedPoints, expectedProgress);
        }

        /// <summary>
        /// Tests the <see cref="TechFieldResearch.RecalculateProgressInPercent" /> function
        /// </summary>
        [Test]
        public void TestReCalculateProgressInPercentWithProgress2()
        {
            const int techLevel = 5;
            const int accumulatedPoints = 575;
            const int expectedProgress = 75;

            AssertRecalculateProgress(techLevel, accumulatedPoints, expectedProgress);
        }

        private static void AssertRecalculateProgress(int techLevel, int accumulatedPoints, int expectedProgress)
        {
            TechFieldResearch research = CreateTechFieldResearch(1, 100); //exponent 1, techlevel will be multiplied by costs (100)
            research.TechLevel = techLevel;
            research.ResearchPointsAccumulated = accumulatedPoints - research.TechField.CalculateResearchPointsForLevel(techLevel) ;
            research.RecalculateProgressInPercent();
            Assert.AreEqual(expectedProgress, research.ProgressInCurrentLevel);
        }


        /// <summary>
        /// Creates the test research calculator.
        /// </summary>
        /// <returns></returns>
        private static FundamentalResearchCalculator CreateTestResearchCalculator()
        {
            return new FundamentalResearchCalculator {CalculateInfo = GameLogicHelper.CreateTestCalculateInfo()};
        }
    }
}